﻿#region Copyright(C) 2010-2010 NCS Pte. Ltd. All rights reserved.
// ==================================================================================================
// Copyright(C) 2010 NCS Pte. Ltd. All rights reserved.
//
// SYSTEM NAME	    : iConnect .Net Application Framework
// COMPONENT ID	    : CBEC.Core.Wcf
// COMPONENT DESC   : Core components for WCF.	
//
// CREATED DATE/BY  : 18 Aug 2010 / Gao Ye
//
// REVISION HISTORY :	
// DATE/BY			SR#/CS/PM#/OTHERS		DESCRIPTION OF CHANGE
// ==================================================================================================
#endregion

using CBEC.Core.Utilities;
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;


namespace CBEC.Core.IoC.Wcf
{
    /// <summary>
    /// A custom InstanceProvider which leverages the service location mechanism to create service instance.
    /// </summary>
    public class ServiceLocatableInstanceProvider : IInstanceProvider
    {
        /// <summary>
        /// Gets or sets the service locator.
        /// </summary>
        /// <value>The service locator.</value>
        public IServiceLocator ServiceLocator { get; private set; }

        /// <summary>
        /// Gets or sets the type of the contract.
        /// </summary>
        /// <value>The type of the contract.</value>
        public Type ContractType { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="ServiceLocatableInstanceProvider"/> class.
        /// </summary>
        /// <param name="serviceLocator">The service locator.</param>
        /// <param name="contractType">Type of the contract.</param>
        public ServiceLocatableInstanceProvider(IServiceLocator serviceLocator, Type contractType)
        {
            Guard.ArgumentNotNull(serviceLocator, "serviceLocator");
            Guard.ArgumentNotNull(contractType, "contractType");
            this.ContractType = contractType;
            this.ServiceLocator = serviceLocator;
        }

        /// <summary>
        /// Returns a service object given the specified <see cref="T:System.ServiceModel.InstanceContext"/> object.
        /// </summary>
        /// <param name="instanceContext">The current <see cref="T:System.ServiceModel.InstanceContext"/> object.</param>
        /// <param name="message">The message that triggered the creation of a service object.</param>
        /// <returns>The service object.</returns>
        public object GetInstance(InstanceContext instanceContext, Message message)
        {
            Type serviceType = instanceContext.Host.Description.ServiceType;
            if (!this.ServiceLocator.IsRegistered(this.ContractType, serviceType))
            {
                this.ServiceLocator.Register(this.ContractType, serviceType);
            }
            return this.ServiceLocator.GetService(this.ContractType);
        }

        /// <summary>
        /// Returns a service object given the specified <see cref="T:System.ServiceModel.InstanceContext"/> object.
        /// </summary>
        /// <param name="instanceContext">The current <see cref="T:System.ServiceModel.InstanceContext"/> object.</param>
        /// <returns>A user-defined service object.</returns>
        public object GetInstance(InstanceContext instanceContext)
        {
            return this.GetInstance(instanceContext, null);
        }

        /// <summary>
        /// Called when an <see cref="T:System.ServiceModel.InstanceContext"/> object recycles a service object.
        /// </summary>
        /// <param name="instanceContext">The service's instance context.</param>
        /// <param name="instance">The service object to be recycled.</param>
        public void ReleaseInstance(InstanceContext instanceContext, object instance)
        {
            IDisposable serviceInstance = instance as IDisposable;
            if (null != serviceInstance)
            {
                serviceInstance.Dispose();
            }
        }
    }
}
